﻿Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Globalization
Imports System.Reflection
Imports System.Runtime.InteropServices
Imports System.Workflow.ComponentModel
Imports System.Workflow.ComponentModel.Compiler
Imports System.Workflow.ComponentModel.Design
Imports System.Xml

Namespace System.Workflow.ComponentModel.Serialization
    Friend NotInheritable Class WorkflowMarkupSerializerMapping
        ' Methods
        Shared Sub New()
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(ThrowActivity).Name, GetType(ThrowActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(ThrowDesigner).Name, GetType(ThrowDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(SuspendActivity).Name, GetType(SuspendActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(SuspendDesigner).Name, GetType(SuspendDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(CancellationHandlerActivity).Name, GetType(CancellationHandlerActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(CancellationHandlerActivityDesigner).Name, GetType(CancellationHandlerActivityDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(CompensateActivity).Name, GetType(CompensateActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(CompensateDesigner).Name, GetType(CompensateDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(CompensationHandlerActivity).Name, GetType(CompensationHandlerActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(CompensationHandlerActivityDesigner).Name, GetType(CompensationHandlerActivityDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(FaultHandlerActivity).Name, GetType(FaultHandlerActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(FaultHandlerActivityDesigner).Name, GetType(FaultHandlerActivityDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(FaultHandlersActivity).Name, GetType(FaultHandlersActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(FaultHandlersActivityDesigner).Name, GetType(FaultHandlersActivityDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(SynchronizationScopeActivity).Name, GetType(SynchronizationScopeActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(SequenceDesigner).Name, GetType(SequenceDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(TransactionScopeActivity).Name, GetType(TransactionScopeActivity))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(TransactionScopeActivityDesigner).Name, GetType(TransactionScopeActivityDesigner))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(PropertySegment).Name, GetType(PropertySegment))
            WorkflowMarkupSerializerMapping.wellKnownTypes.Add(GetType(CompensatableTransactionScopeActivity).Name, GetType(CompensatableTransactionScopeActivity))
            WorkflowMarkupSerializerMapping.wellKnownMappings = New List([Of] WorkflowMarkupSerializerMapping)
            WorkflowMarkupSerializerMapping.Activities = New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.Activities", "System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(WorkflowMarkupSerializerMapping.Activities)
            WorkflowMarkupSerializerMapping.ComponentModel = New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.ComponentModel", Assembly.GetExecutingAssembly.FullName)
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(WorkflowMarkupSerializerMapping.ComponentModel)
            WorkflowMarkupSerializerMapping.Serialization = New WorkflowMarkupSerializerMapping("x", "http://schemas.microsoft.com/winfx/2006/xaml", "System.Workflow.ComponentModel.Serialization", Assembly.GetExecutingAssembly.FullName)
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(WorkflowMarkupSerializerMapping.Serialization)
            WorkflowMarkupSerializerMapping.Rules = New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.Activities.Rules", "System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35")
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(WorkflowMarkupSerializerMapping.Rules)
            WorkflowMarkupSerializerMapping.ComponentModelDesign = New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.ComponentModel.Design", Assembly.GetExecutingAssembly.FullName)
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(WorkflowMarkupSerializerMapping.ComponentModelDesign)
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.Runtime", "System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL"))
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.ComponentModel.Compiler", Assembly.GetExecutingAssembly.FullName))
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.Activities.Rules.Design", "System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"))
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.Runtime.Configuration", "System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL"))
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.Runtime.Hosting", "System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL"))
            WorkflowMarkupSerializerMapping.wellKnownMappings.Add(New WorkflowMarkupSerializerMapping("wf", "http://schemas.microsoft.com/winfx/2006/xaml/workflow", "System.Workflow.Runtime.Tracking", "System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL"))
        End Sub

        Public Sub New(ByVal prefix As String, ByVal xmlNamespace As String, ByVal clrNamespace As String, ByVal assemblyName As String)
            If (prefix Is Nothing) Then
                Throw New ArgumentNullException("prefix")
            End If
            If (xmlNamespace Is Nothing) Then
                Throw New ArgumentNullException("xmlNamespace")
            End If
            If (clrNamespace Is Nothing) Then
                Throw New ArgumentNullException("clrNamespace")
            End If
            If (assemblyName Is Nothing) Then
                Throw New ArgumentNullException("assemblyName")
            End If
            Me.prefix = prefix
            Me.xmlns = xmlNamespace
            Me.clrns = clrNamespace
            Me.asmName = assemblyName
        End Sub

        Public Overrides Function Equals(ByVal value As Object) As Boolean
            Return (TypeOf value Is WorkflowMarkupSerializerMapping AndAlso ((Me.ClrNamespace = [TryCast](value,WorkflowMarkupSerializerMapping).ClrNamespace) AndAlso (Me.AssemblyName = [TryCast](value,WorkflowMarkupSerializerMapping).AssemblyName)))
        End Function

        Private Shared Function GetFormatedXmlNamespace(ByVal clrNamespace As String, ByVal assemblyName As String) As String
            Dim str As String = "clr-namespace:"
            str = (str & If(String.IsNullOrEmpty(clrNamespace), "{Global}", clrNamespace))
            If Not String.IsNullOrEmpty(assemblyName) Then
                str = (str & ";Assembly=" & assemblyName)
            End If
            Return str
        End Function

        Public Overrides Function GetHashCode() As Integer
            Return (Me.ClrNamespace.GetHashCode Xor Me.AssemblyName.GetHashCode)
        End Function

        Friend Shared Sub GetMappingFromType(ByVal manager As WorkflowMarkupSerializationManager, ByVal type As Type, <Out> ByRef matchingMapping As WorkflowMarkupSerializerMapping, <Out> ByRef collectedMappings As IList([Of] WorkflowMarkupSerializerMapping))
            matchingMapping = Nothing
            collectedMappings = New List([Of] WorkflowMarkupSerializerMapping)
            Dim clrNamespace As String = If((Not type.Namespace Is Nothing), type.Namespace, String.Empty)
            Dim xmlNamespace As String = String.Empty
            Dim fullName As String = String.Empty
            Dim prefix As String = String.Empty
            fullName = type.Assembly.FullName
            If type.Assembly.FullName.Equals("System.Workflow.Runtime, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL", StringComparison.Ordinal) Then
                xmlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/workflow"
                prefix = "wf"
            End If
            If type.Assembly.FullName.Equals("System.Workflow.Activities, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35", StringComparison.Ordinal) Then
                xmlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/workflow"
                prefix = "wf"
            ElseIf (type.Assembly Is Assembly.GetExecutingAssembly) Then
                xmlNamespace = "http://schemas.microsoft.com/winfx/2006/xaml/workflow"
                prefix = "wf"
            End If
            If (xmlNamespace.Length = 0) Then
                Dim attribute As XmlnsDefinitionAttribute
                For Each attribute In type.Assembly.GetCustomAttributes(GetType(XmlnsDefinitionAttribute), True)
                    xmlNamespace = attribute.XmlNamespace
                    fullName = attribute.AssemblyName
                    If (type.Assembly Is manager.LocalAssembly) Then
                        fullName = String.Empty
                    ElseIf String.IsNullOrEmpty(fullName) Then
                        fullName = type.Assembly.FullName
                    End If
                    If String.IsNullOrEmpty(xmlNamespace) Then
                        xmlNamespace = WorkflowMarkupSerializerMapping.GetFormatedXmlNamespace(clrNamespace, fullName)
                    End If
                    prefix = WorkflowMarkupSerializerMapping.GetPrefix(manager, type.Assembly, xmlNamespace)
                    Dim item As New WorkflowMarkupSerializerMapping(prefix, xmlNamespace, clrNamespace, fullName)
                    If (attribute.ClrNamespace.Equals(clrNamespace, StringComparison.Ordinal) AndAlso (matchingMapping Is Nothing)) Then
                        matchingMapping = item
                    Else
                        collectedMappings.Add(item)
                    End If
                Next
            End If
            If (matchingMapping Is Nothing) Then
                If (type.Assembly Is manager.LocalAssembly) Then
                    fullName = String.Empty
                ElseIf String.IsNullOrEmpty(fullName) Then
                    fullName = type.Assembly.FullName
                End If
                xmlNamespace = WorkflowMarkupSerializerMapping.GetFormatedXmlNamespace(clrNamespace, fullName)
                If String.IsNullOrEmpty(prefix) Then
                    prefix = WorkflowMarkupSerializerMapping.GetPrefix(manager, type.Assembly, xmlNamespace)
                End If
                matchingMapping = New WorkflowMarkupSerializerMapping(prefix, xmlNamespace, clrNamespace, fullName)
            End If
        End Sub

        Friend Shared Sub GetMappingsFromXmlNamespace(ByVal serializationManager As WorkflowMarkupSerializationManager, ByVal xmlNamespace As String, <Out> ByRef matchingMappings As IList([Of] WorkflowMarkupSerializerMapping), <Out> ByRef collectedMappings As IList([Of] WorkflowMarkupSerializerMapping))
            matchingMappings = New List([Of] WorkflowMarkupSerializerMapping)
            collectedMappings = New List([Of] WorkflowMarkupSerializerMapping)
            Dim reader As XmlReader = [TryCast](serializationManager.WorkflowMarkupStack.Item(GetType(XmlReader)),XmlReader)
            If (Not reader Is Nothing) Then
                If xmlNamespace.StartsWith("clr-namespace:", StringComparison.OrdinalIgnoreCase) Then
                    Dim flag As Boolean = False
                    Dim clrNamespace As String = xmlNamespace.Substring("clr-namespace:".Length).Trim
                    Dim assemblyName As String = String.Empty
                    Dim index As Integer = clrNamespace.IndexOf(";"c)
                    If (index <> -1) Then
                        assemblyName = If(((index + 1) < clrNamespace.Length), clrNamespace.Substring((index + 1)).Trim, String.Empty)
                        clrNamespace = clrNamespace.Substring(0, index).Trim
                        If Not assemblyName.StartsWith("Assembly=", StringComparison.OrdinalIgnoreCase) Then
                            flag = True
                        End If
                        assemblyName = assemblyName.Substring("Assembly=".Length)
                    End If
                    If Not flag Then
                        If clrNamespace.Equals("{Global}", StringComparison.OrdinalIgnoreCase) Then
                            clrNamespace = String.Empty
                        End If
                        matchingMappings.Add(New WorkflowMarkupSerializerMapping(reader.Prefix, xmlNamespace, clrNamespace, assemblyName))
                    End If
                Else
                    Dim list As New List([Of] Assembly)
                    If (Not serializationManager.LocalAssembly Is Nothing) Then
                        list.Add(serializationManager.LocalAssembly)
                    End If
                    Dim service As ITypeProvider = [TryCast](serializationManager.GetService(GetType(ITypeProvider)),ITypeProvider)
                    If (Not service Is Nothing) Then
                        list.AddRange(service.ReferencedAssemblies)
                    End If
                    Dim assembly As Assembly
                    For Each assembly In list
                        Dim customAttributes As Object() = [assembly].GetCustomAttributes(GetType(XmlnsDefinitionAttribute), True)
                        If (Not customAttributes Is Nothing) Then
                            Dim attribute As XmlnsDefinitionAttribute
                            For Each attribute In customAttributes
                                Dim fullName As String = String.Empty
                                If (Not serializationManager.LocalAssembly Is [assembly]) Then
                                    If ((Not attribute.AssemblyName Is Nothing) AndAlso (attribute.AssemblyName.Trim.Length > 0)) Then
                                        fullName = attribute.AssemblyName
                                    Else
                                        fullName = [assembly].FullName
                                    End If
                                End If
                                If attribute.XmlNamespace.Equals(xmlNamespace, StringComparison.Ordinal) Then
                                    matchingMappings.Add(New WorkflowMarkupSerializerMapping(reader.Prefix, xmlNamespace, attribute.ClrNamespace, fullName))
                                Else
                                    collectedMappings.Add(New WorkflowMarkupSerializerMapping(reader.Prefix, xmlNamespace, attribute.ClrNamespace, fullName))
                                End If
                            Next
                        End If
                    Next
                End If
            End If
        End Sub

        Private Shared Function GetPrefix(ByVal manager As WorkflowMarkupSerializationManager, ByVal [assembly] As Assembly, ByVal xmlNamespace As String) As String
            Dim prefix As String = String.Empty
            Dim customAttributes As Object() = [assembly].GetCustomAttributes(GetType(XmlnsPrefixAttribute), True)
            If (Not customAttributes Is Nothing) Then
                Dim attribute As XmlnsPrefixAttribute
                For Each attribute In customAttributes
                    If attribute.XmlNamespace.Equals(xmlNamespace, StringComparison.Ordinal) Then
                        prefix = attribute.Prefix
                        Exit For
                    End If
                Next
            End If
            If (String.IsNullOrEmpty(prefix) OrElse Not WorkflowMarkupSerializerMapping.IsNamespacePrefixUnique(prefix, manager.PrefixBasedMappings.Keys)) Then
                Dim str2 As String = If(String.IsNullOrEmpty(prefix), "ns", prefix)
                Dim num As Integer = 0
                prefix = (str2 & String.Format(CultureInfo.InvariantCulture, "{0}", New Object() { num++ }))
                Do While Not WorkflowMarkupSerializerMapping.IsNamespacePrefixUnique(prefix, manager.PrefixBasedMappings.Keys)
                    prefix = (str2 & String.Format(CultureInfo.InvariantCulture, "{0}", New Object() { num++ }))
                Loop
            End If
            Return prefix
        End Function

        Private Shared Function IsNamespacePrefixUnique(ByVal prefix As String, ByVal existingPrefixes As ICollection) As Boolean
            Dim str As String
            For Each str In existingPrefixes
                If str.Equals(prefix, StringComparison.Ordinal) Then
                    Return False
                End If
            Next
            Return True
        End Function

        Friend Shared Function ResolveWellKnownTypes(ByVal manager As WorkflowMarkupSerializationManager, ByVal xmlns As String, ByVal typeName As String) As Type
            Dim type As Type = Nothing
            Dim list As New List([Of] WorkflowMarkupSerializerMapping)
            If xmlns.Equals("http://schemas.microsoft.com/winfx/2006/xaml/workflow", StringComparison.Ordinal) Then
                If Not WorkflowMarkupSerializerMapping.wellKnownTypes.TryGetValue(typeName, type) Then
                    If typeName.EndsWith("Activity", StringComparison.OrdinalIgnoreCase) Then
                        list.Add(WorkflowMarkupSerializerMapping.Activities)
                        list.Add(WorkflowMarkupSerializerMapping.ComponentModel)
                    ElseIf typeName.EndsWith("Theme", StringComparison.OrdinalIgnoreCase) Then
                        list.Add(WorkflowMarkupSerializerMapping.ComponentModelDesign)
                        list.Add(WorkflowMarkupSerializerMapping.Activities)
                    ElseIf (typeName.StartsWith("Rule", StringComparison.OrdinalIgnoreCase) OrElse typeName.EndsWith("Action", StringComparison.OrdinalIgnoreCase)) Then
                        list.Add(WorkflowMarkupSerializerMapping.Rules)
                    End If
                End If
            ElseIf xmlns.Equals("http://schemas.microsoft.com/winfx/2006/xaml", StringComparison.Ordinal) Then
                list.Add(WorkflowMarkupSerializerMapping.Serialization)
            End If
            If (type Is Nothing) Then
                Dim mapping As WorkflowMarkupSerializerMapping
                For Each mapping In list
                    Dim str As String = String.Concat(New String() { mapping.ClrNamespace, ".", typeName, ", ", mapping.AssemblyName })
                    type = manager.GetType(str)
                    If (Not type Is Nothing) Then
                        Return type
                    End If
                Next
            End If
            Return type
        End Function


        ' Properties
        Public ReadOnly Property AssemblyName As String
            Get
                Return Me.asmName
            End Get
        End Property

        Public ReadOnly Property ClrNamespace As String
            Get
                Return Me.clrns
            End Get
        End Property

        Public ReadOnly Property Prefix As String
            Get
                Return Me.prefix
            End Get
        End Property

        Friend Shared ReadOnly Property WellKnownMappings As IList([Of] WorkflowMarkupSerializerMapping)
            Get
                Return WorkflowMarkupSerializerMapping.wellKnownMappings
            End Get
        End Property

        Public ReadOnly Property XmlNamespace As String
            Get
                Return Me.xmlns
            End Get
        End Property


        ' Fields
        Private Shared ReadOnly Activities As WorkflowMarkupSerializerMapping
        Private asmName As String = String.Empty
        Private clrns As String = String.Empty
        Private Shared ReadOnly ComponentModel As WorkflowMarkupSerializerMapping
        Private Shared ReadOnly ComponentModelDesign As WorkflowMarkupSerializerMapping
        Private prefix As String = String.Empty
        Private Shared ReadOnly Rules As WorkflowMarkupSerializerMapping
        Private Shared ReadOnly Serialization As WorkflowMarkupSerializerMapping
        Private Shared ReadOnly wellKnownMappings As List([Of] WorkflowMarkupSerializerMapping)
        Private Shared ReadOnly wellKnownTypes As Dictionary([Of] String, Type) = New Dictionary([Of] String, Type)
        Private xmlns As String = String.Empty
    End Class
End Namespace

